using System;
using System.Collections.Generic;
using System.Linq;
using DevExpress.XtraCharts;
using DevExpress.Utils;

namespace ChartControlHelper
{
    /// <summary>
    /// DevExpress ChartControl 辅助类
    /// </summary>
    public static class ChartControlHelper
    {
        /// <summary>
        /// 设置图表的横纵轴数据
        /// </summary>
        /// <param name="chartControl">图表控件</param>
        /// <param name="xAxisValues">横轴数据（可以是字符串、数字或日期）</param>
        /// <param name="yAxisValues">纵轴数据（数值）</param>
        /// <param name="seriesName">系列名称</param>
        /// <param name="chartType">图表类型，默认为柱状图</param>
        public static void SetChartData<T>(ChartControl chartControl, 
            IEnumerable<T> xAxisValues, 
            IEnumerable<double> yAxisValues, 
            string seriesName = "Series1", 
            ViewType chartType = ViewType.Bar)
        {
            if (chartControl == null)
                throw new ArgumentNullException(nameof(chartControl));
            
            if (xAxisValues == null || yAxisValues == null)
                throw new ArgumentNullException("轴数据不能为空");

            var xValues = xAxisValues.ToList();
            var yValues = yAxisValues.ToList();

            if (xValues.Count != yValues.Count)
                throw new ArgumentException("横轴和纵轴数据数量必须相等");

            // 清除现有数据
            chartControl.Series.Clear();

            // 创建新的系列
            Series series = new Series(seriesName, chartType);

            // 添加数据点
            for (int i = 0; i < xValues.Count; i++)
            {
                series.Points.Add(new SeriesPoint(xValues[i], yValues[i]));
            }

            // 添加系列到图表
            chartControl.Series.Add(series);

            // 自动调整轴范围
            AutoAdjustAxisRange(chartControl, yValues);
        }

        /// <summary>
        /// 设置多系列图表数据
        /// </summary>
        /// <param name="chartControl">图表控件</param>
        /// <param name="xAxisValues">横轴数据</param>
        /// <param name="seriesData">多系列数据字典，Key为系列名称，Value为纵轴数据</param>
        /// <param name="chartType">图表类型</param>
        public static void SetMultiSeriesChartData<T>(ChartControl chartControl,
            IEnumerable<T> xAxisValues,
            Dictionary<string, IEnumerable<double>> seriesData,
            ViewType chartType = ViewType.Bar)
        {
            if (chartControl == null)
                throw new ArgumentNullException(nameof(chartControl));

            if (xAxisValues == null || seriesData == null)
                throw new ArgumentNullException("数据不能为空");

            var xValues = xAxisValues.ToList();
            var allYValues = new List<double>();

            // 清除现有数据
            chartControl.Series.Clear();

            foreach (var kvp in seriesData)
            {
                var yValues = kvp.Value.ToList();
                
                if (xValues.Count != yValues.Count)
                    throw new ArgumentException($"系列 '{kvp.Key}' 的数据数量与横轴数据数量不匹配");

                // 创建系列
                Series series = new Series(kvp.Key, chartType);

                // 添加数据点
                for (int i = 0; i < xValues.Count; i++)
                {
                    series.Points.Add(new SeriesPoint(xValues[i], yValues[i]));
                }

                chartControl.Series.Add(series);
                allYValues.AddRange(yValues);
            }

            // 自动调整轴范围
            AutoAdjustAxisRange(chartControl, allYValues);
        }

        /// <summary>
        /// 自动调整轴范围
        /// </summary>
        /// <param name="chartControl">图表控件</param>
        /// <param name="yValues">纵轴数据</param>
        private static void AutoAdjustAxisRange(ChartControl chartControl, IEnumerable<double> yValues)
        {
            if (!yValues.Any()) return;

            var minValue = yValues.Min();
            var maxValue = yValues.Max();
            var range = maxValue - minValue;

            double adjustedMin, adjustedMax;

            // 处理最小值和最大值相等的情况
            if (Math.Abs(range) < double.Epsilon) // range == 0
            {
                // 如果所有值都相等，创建一个合理的范围
                var baseValue = minValue;
                if (Math.Abs(baseValue) < double.Epsilon) // baseValue == 0
                {
                    // 如果值为0，设置范围为 -1 到 1
                    adjustedMin = -1;
                    adjustedMax = 1;
                }
                else
                {
                    // 如果值不为0，以该值为中心创建20%的范围
                    var margin = Math.Abs(baseValue) * 0.1;
                    adjustedMin = baseValue - margin;
                    adjustedMax = baseValue + margin;
                }
            }
            else
            {
                // 正常情况：添加10%的边距
                var margin = range * 0.1;
                adjustedMin = minValue - margin;
                adjustedMax = maxValue + margin;
            }

            // 确保最小值不小于0（如果原始最小值>=0）
            if (minValue >= 0 && adjustedMin < 0)
                adjustedMin = 0;

            // 获取图表的主要Y轴
            if (chartControl.Diagram is XYDiagram diagram)
            {
                // 设置Y轴范围
                diagram.AxisY.Range.SetMinMaxValues(adjustedMin, adjustedMax);
                diagram.AxisY.Range.SideMarginsEnabled = false;

                // 设置X轴属性
                diagram.AxisX.Range.SideMarginsEnabled = true;
            }
        }

        /// <summary>
        /// 手动设置轴范围
        /// </summary>
        /// <param name="chartControl">图表控件</param>
        /// <param name="yMin">Y轴最小值</param>
        /// <param name="yMax">Y轴最大值</param>
        /// <param name="xMin">X轴最小值（可选）</param>
        /// <param name="xMax">X轴最大值（可选）</param>
        public static void SetAxisRange(ChartControl chartControl, 
            double? yMin = null, double? yMax = null,
            object xMin = null, object xMax = null)
        {
            if (chartControl?.Diagram is XYDiagram diagram)
            {
                // 设置Y轴范围
                if (yMin.HasValue && yMax.HasValue)
                {
                    diagram.AxisY.Range.SetMinMaxValues(yMin.Value, yMax.Value);
                }
                else if (yMin.HasValue)
                {
                    diagram.AxisY.Range.SetMinMaxValues(yMin.Value, diagram.AxisY.Range.MaxValue);
                }
                else if (yMax.HasValue)
                {
                    diagram.AxisY.Range.SetMinMaxValues(diagram.AxisY.Range.MinValue, yMax.Value);
                }

                // 设置X轴范围（如果提供）
                if (xMin != null && xMax != null)
                {
                    diagram.AxisX.Range.SetMinMaxValues(xMin, xMax);
                }
            }
        }

        /// <summary>
        /// 设置轴标题和格式
        /// </summary>
        /// <param name="chartControl">图表控件</param>
        /// <param name="xAxisTitle">X轴标题</param>
        /// <param name="yAxisTitle">Y轴标题</param>
        /// <param name="yAxisFormat">Y轴数值格式</param>
        public static void SetAxisTitlesAndFormat(ChartControl chartControl,
            string xAxisTitle = null,
            string yAxisTitle = null,
            string yAxisFormat = null)
        {
            if (chartControl?.Diagram is XYDiagram diagram)
            {
                // 设置轴标题
                if (!string.IsNullOrEmpty(xAxisTitle))
                {
                    diagram.AxisX.Title.Text = xAxisTitle;
                    diagram.AxisX.Title.Visibility = DefaultBoolean.True;
                }

                if (!string.IsNullOrEmpty(yAxisTitle))
                {
                    diagram.AxisY.Title.Text = yAxisTitle;
                    diagram.AxisY.Title.Visibility = DefaultBoolean.True;
                }

                // 设置Y轴数值格式
                if (!string.IsNullOrEmpty(yAxisFormat))
                {
                    diagram.AxisY.Label.TextPattern = yAxisFormat;
                }
            }
        }


        /// <summary>
        /// 设置Y轴为百分数格式
        /// </summary>
        /// <param name="chartControl">图表控件</param>
        /// <param name="decimalPlaces">小数位数，默认为1位</param>
        /// <param name="multiplyBy100">是否将数值乘以100，默认为true（适用于0-1范围的小数）</param>
        public static void SetYAxisAsPercentage(ChartControl chartControl, int decimalPlaces = 1, bool multiplyBy100 = true)
        {
            if (chartControl?.Diagram is XYDiagram diagram)
            {
                if (multiplyBy100)
                {
                    // 适用于0-1范围的小数，自动乘以100显示为百分数
                    // 使用P格式自动将小数转换为百分数
                    var format = decimalPlaces > 0 ? $"{{V:P{decimalPlaces}}}" : "{V:P0}";
                    diagram.AxisY.Label.TextPattern = format;
                }
                else
                {
                    // 适用于已经是百分数值的数据（如50表示50%）
                    var format = decimalPlaces > 0 ? $"{{V:F{decimalPlaces}}}%" : "{V:F0}%";
                    diagram.AxisY.Label.TextPattern = format;
                }

                // 同时设置数据点标签格式
                foreach (Series series in chartControl.Series)
                {
                    if (multiplyBy100)
                    {
                        var labelFormat = decimalPlaces > 0 ? $"{{V:P{decimalPlaces}}}" : "{V:P0}";
                        series.Label.TextPattern = labelFormat;
                    }
                    else
                    {
                        var labelFormat = decimalPlaces > 0 ? $"{{V:F{decimalPlaces}}}%" : "{V:F0}%";
                        series.Label.TextPattern = labelFormat;
                    }
                    series.LabelsVisibility = DevExpress.Utils.DefaultBoolean.True;
                }
            }
        }

        /// <summary>
        /// 设置图表数据并自动应用百分数格式
        /// </summary>
        /// <param name="chartControl">图表控件</param>
        /// <param name="xAxisValues">横轴数据</param>
        /// <param name="yAxisValues">纵轴数据（百分数值）</param>
        /// <param name="seriesName">系列名称</param>
        /// <param name="chartType">图表类型</param>
        /// <param name="decimalPlaces">百分数小数位数</param>
        /// <param name="multiplyBy100">是否将数值乘以100</param>
        public static void SetChartDataWithPercentage<T>(ChartControl chartControl,
            IEnumerable<T> xAxisValues,
            IEnumerable<double> yAxisValues,
            string seriesName = "Series1",
            ViewType chartType = ViewType.Bar,
            int decimalPlaces = 1,
            bool multiplyBy100 = true)
        {
            // 设置图表数据
            SetChartData(chartControl, xAxisValues, yAxisValues, seriesName, chartType);

            // 应用百分数格式
            SetYAxisAsPercentage(chartControl, decimalPlaces, multiplyBy100);
        }
    }

    /// <summary>
    /// 使用示例类
    /// </summary>
    public class ChartExample
    {
        public void ExampleUsage(ChartControl chartControl)
        {
            // 示例1：简单的柱状图
            var months = new[] { "1月", "2月", "3月", "4月", "5月", "6月" };
            var sales = new[] { 1200.5, 1500.0, 1800.3, 1350.7, 2100.2, 1950.8 };
            
            ChartControlHelper.SetChartData(chartControl, months, sales, "销售额", ViewType.Bar);
            ChartControlHelper.SetAxisTitlesAndFormat(chartControl, "月份", "销售额", "{V:C}"); // 货币格式

            // 示例2：多系列图表
            var categories = new[] { "产品A", "产品B", "产品C", "产品D" };
            var multiSeriesData = new Dictionary<string, IEnumerable<double>>
            {
                { "2023年", new[] { 100.0, 150.0, 120.0, 180.0 } },
                { "2024年", new[] { 120.0, 160.0, 140.0, 200.0 } }
            };
            
            ChartControlHelper.SetMultiSeriesChartData(chartControl, categories, multiSeriesData, ViewType.Line);
            
            // 示例3：手动设置轴范围
            ChartControlHelper.SetAxisRange(chartControl, yMin: 0, yMax: 250);
        }
    }
}